import { Component, Injector, Input, forwardRef, Output, EventEmitter } from '@angular/core'
import { NG_VALUE_ACCESSOR } from '@angular/forms'
import { Observable } from 'rxjs'
import { map } from 'rxjs/operators'
import { deepCopy } from '@delon/util'

import { AbstractCustomMultipleSelectComponent } from '../custom-select/custom-multiple-select.component'
import { IGenericPagination } from '@shared/interfaces/pagination'
import { CurrencyService } from '@shared/services/currency.service'
import { IOptionSorter } from '../custom-select/custom-select.interface'
import { Currency } from '@shared/interfaces/common'
import { objectArrayDeduplication } from 'app/utils/helpers'

interface ICurrencyParams {
  insCode?: string
  intStoreCode?: string
  kw?: string // 检索字段，包含 code | number | name
}
const TYPE_STR = 'code'
@Component({
  selector: 'app-currency-select',
  templateUrl: './currency-select.component.html',
  styles: [],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CurrencySelectComponent),
      multi: true,
    },
  ],
})
export class CurrencySelectComponent extends AbstractCustomMultipleSelectComponent<Currency, {}>
  implements IOptionSorter {
  constructor(private currencyService: CurrencyService, public injector: Injector) {
    super(injector)
  }

  @Input()
  set insCode(val: string) {
    this._params.insCode = val
    this.searchChange$.next(this.getParams())
  }

  @Input()
  set intStoreCode(val: string) {
    this._params.intStoreCode = val
    this.searchChange$.next(this.getParams())
  }

  @Input() type: 'string' | 'obj' = 'obj'

  _params: ICurrencyParams = {
    insCode: '',
    intStoreCode: '',
  }

  /** 是否允许删除，默认可以 */
  @Input() allowClear = true

  @Input() maxTagCount = 5
  @Output() requiredEvent: EventEmitter<any> = new EventEmitter()

  deduplicate(list: Currency[]): Currency[] {
    return objectArrayDeduplication(list, TYPE_STR)
  }

  sortFn: () => ((a: Currency, b: Currency) => number) = () => {
    let codes: string[] = []
    if (Array.isArray(this._value)) {
      codes = this._value.map(o => o.code)
    }
    return (a: Currency, b: Currency) => {
      if (codes.includes(a.code)) {
        return -1
      }

      return 1
    }
  }

  compareFn = (o1: Currency, o2: Currency) => {
    if (this.type === 'obj') {
      return o1 && o2 ? o1.code === o2.code : o1 === o2
    }
    if (this.type === 'string') {
      return o1 === o2
    }
  }

  /** 筛选函数 */
  filterFn = (c: Currency, kw: string): boolean => {
    return this.weakInclude(c.code, kw) || this.weakInclude(c.number, kw) || this.weakInclude(c.name, kw)
  }

  /** 弱匹配 */
  weakInclude(str: string, kw: string): boolean {
    return str.toLocaleLowerCase().includes(kw.toLocaleLowerCase())
  }

  query(params: ICurrencyParams): Observable<IGenericPagination<Currency>> {
    const { kw } = params
    return this.currencyService.getList(params.insCode, params.intStoreCode).pipe(
      map(currencies => {
        const size = currencies.length
        const filterCurrencies = !!kw
          ? currencies.filter(c => this.filterFn(c , kw))
          : currencies
        return {
          count: size,
          page: 1,
          size,
          total: size,
          data: filterCurrencies,
        }
      }),
    )
  }

  getParams(): {} {
    return this._params
  }

  onSearch(kw: string): void {
    this.isLoading = true
    this._options = []
    this.searchChange$.next({...this.getParams(), kw})
  }

  modelChange(newVal: Currency | Currency[]): void {
    if (Array.isArray(newVal)) {
      const oldVal = this._value as Currency[]
      if (oldVal && oldVal.length > 0 && newVal.length === 0 && this.required) {
        this.value = deepCopy(oldVal)
        this.requiredEvent.emit()
      } else {
        this.value = newVal
      }
      this.refreshRequest$.next(`refresh at ${new Date().getTime()}`)
      return
    }

    if (!this.multiple) {
      this.value = newVal
      return
    }
  }
  /**
   * 当币种为单值时,value是一个对象或字符串
   * 当币种为多值时,value是一个对象数组或字符数组
   * @param value 币种
   */
  writeValue(value: Currency): void {
    this._value = value
    if (value) {
      if (JSON.stringify(value) === '{}') { // 处理默认值为{}的情况
        this._options = [...this._options]
      } else {
        this._options = Array.isArray(value) ? [...value, ...this._options] : [value, ...this._options]
      }
      this.refreshRequest$.next('refresh')
    }
    setTimeout(() => this.cdRef.detectChanges(), 0)
  }
}
